﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpSoft.Lexing;

namespace SharpSoft.Documentation.Html.CSS
{
    /// <summary>
    /// CSS选择器词法分析程序
    /// </summary>
    internal class SelectorLexer : _TextLexer
    {
        public SelectorLexer(TextSource source)
            : base(source)
        {
        }
        public SelectorLexer(string source)
            : base(source)
        {

        }

        internal new void SkipWhiteSpace()
        {
            base.SkipWhiteSpace();
        }
        /// <summary>
        /// 从当前位置读取一个标识
        /// </summary>
        /// <returns></returns>
        public SelectorToken ReadToken()
        {
            char c = Current;
            char p = Peek();
            if (EOS())
                return SelectorToken.EndToken;
            if (c == '{')
                return SelectorToken.EndToken;
            if (c == '*')
            {
                if (p == '=')
                {//作为*=符号
                    Next(2);
                    return new SelectorToken(Position, 2, SelectorTokenType.MatchTypeContains);
                }
                else
                {//作为表示所有标签的通配符
                    Next();
                    return new SelectorToken(Position, 1, SelectorTokenType.Literal, c.ToString());
                }
            }
            if (c == '~')
            {
                if (p == '=')
                {//作为~=符号
                    Next(2);
                    return new SelectorToken(Position, 2, SelectorTokenType.MatchTypeItem);
                }
                else
                {//作为~符号
                    Next();
                    return new SelectorToken(Position, 1, SelectorTokenType.NextN);
                }
            }
            if (c == '|')
            {
                if (p == '=')
                {//作为|=符号
                    Next(2);
                    SkipWhiteSpace();
                    return new SelectorToken(Position, 2, SelectorTokenType.MatchTypeSpecific);
                }
                else
                    InvalidChar();
            }
            if (c == '^')
            {
                if (p == '=')
                {//作为^=符号
                    Next(2);
                    SkipWhiteSpace();
                    return new SelectorToken(Position, 2, SelectorTokenType.MatchTypeStartWith);
                }
                else
                    InvalidChar();
            }
            if (c == '$')
            {
                if (p == '=')
                {//作为$=符号
                    Next(2);
                    SkipWhiteSpace();
                    return new SelectorToken(Position, 2, SelectorTokenType.MatchTypeEndWith);
                }
                else
                    InvalidChar();
            }
            SelectorToken t;
            if (c == '@')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.Frame);
                Next();
            }
            else if (c == '.')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.Class);
                Next();
            }
            else if (c == '#')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.Id);
                Next();
            }
            else if (c == ' ' || c == '\r' || c == '\n')//空格或换行符
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.Progeny);
                Next();
                SkipWhiteSpace();////忽略之后的空白，降低解释器压力
            }
            else if (c == '>')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.Child);
                Next();
                SkipWhiteSpace();//忽略之后的空白，降低解释器压力
            }
            else if (c == '+')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.NextOne);
                Next();
                SkipWhiteSpace();//忽略之后的空白，降低解释器压力
            }
            else if (c == '[')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.OpenBracket);
                Next();
                SkipWhiteSpace();
            }
            else if (c == ']')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.CloseBracket);
                Next();
            }
            else if (c == '=')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.MatchTypeEqual);
                Next();
            }
            else if (c == ',')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.Comma);
                Next();
                SkipWhiteSpace();
            }
            else if (c == ':')
            {
                t = new SelectorToken(Position, 1, SelectorTokenType.PseudoClass);
                Next();
                SkipWhiteSpace();
            }
            else if (c == '(')
            {//伪类参数
                int pos = Position;
                string str = ReadBetween('(', ')');
                t = new SelectorToken(pos, str.Length + 2, SelectorTokenType.PseudoClassParameter, str);
            }
            else if (c == '"' || c == '\'')
            {//字符串
                int pos = Position;
                string str = ReadString();
                t = new SelectorToken(pos, str.Length + 2, SelectorTokenType.String, str);
            }
            else if (IsCSSIdentifier(c))
            {
                int pos = Position;
                string str = ReadLiteral();
                t = new SelectorToken(pos, str.Length, SelectorTokenType.Literal, str);
            }
            else
            {
                InvalidChar();
                t = SelectorToken.EndToken;//无意义，避免编译器报错
            }
            return t;
        }
        /// <summary>
        /// 读取一个常规量（允许作为类名/Id/标签名称和属性名称的标识符）
        /// </summary>
        /// <returns></returns>
        private string ReadLiteral()
        {
            char c = Current;
            StringBuilder sb = new StringBuilder(10);
            while (IsCSSIdentifier(c))
            {
                sb.Append(c);
                c = Next();
            }

            return sb.ToString();
        }

        private bool IsCSSIdentifier(char c)
        {
            return char.IsLetterOrDigit(c) || c == '_' || c == '-';
        }

    }
}
